/**
 ******************************************************************************
 * @file           : bsp_24cxx.c
 * @brief          : AT24CXX EEPROM Driver Implementation
 ******************************************************************************
 * @attention
 *
 * AT24CXX系列EEPROM驱动程序实现
 * 支持AT24C01~AT24C256系列芯片
 * 支持硬件I2C和软件I2C两种通信方式
 * 提供完整的读写、检测功能
 *
 ******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "./BSP/24CXX/bsp_24cxx.h"
#include "./BSP/24CXX/bsp_24cxx_config.h"

/* Private includes ----------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/

/* Private functions ---------------------------------------------------------*/

/* Exported functions --------------------------------------------------------*/

/**
 * @brief       初始化AT24CXX EEPROM驱动
 *
 * @param       无
 *
 * @retval      无
 *
 * @note        硬件I2C模式下，自动完成I2C GPIO和外设初始化
 *              软件I2C模式下，调用软件I2C初始化函数
 *              使用其他AT24CXX函数前必须先调用此函数
 */
void at24cxx_init(void)
{
#if (USE_HARDWARE_I2C == 1)
    IIC_Init();                     /* 初始化硬件I2C */
    log_i("AT24CXX初始化完成（使用硬件I2C）");
#else
    iic_init();                     /* 初始化软件I2C */
    log_i("AT24CXX初始化完成（使用软件I2C）");
#endif
}

/**
 * @brief       检测AT24CXX EEPROM是否正常工作
 *
 * @param       无
 *
 * @retval      AT24CXX_OK: 检测成功
 * @retval      AT24CXX_ERROR_CHECK: 检测失败
 *
 * @note        使用EEPROM的最后一个地址进行测试，避免影响用户数据
 *              首次使用时会在测试地址写入0x55
 *              检测原理：读取末地址->验证测试值->不匹配则写入测试值->重新验证
 */
int8_t at24cxx_check(void)
{
    uint8_t temp;
    uint16_t test_addr = EE_TYPE;
    int8_t ret;
    
    /* 先读取测试地址的数据，避免每次开机都写EEPROM */
    ret = at24cxx_read_one_byte(test_addr, &temp);
    if (ret != AT24CXX_OK)
    {
        log_e("读取测试地址失败");
        return AT24CXX_ERROR_CHECK;
    }
    
    if (temp == AT24CXX_TEST_VALUE)
    {
        log_i("%s检测成功 (容量:%u字节)", at24cxx_get_model_name(), at24cxx_get_capacity());
        return AT24CXX_OK;
    }
    else
    {
        log_w("首次使用，写入测试值0x%02X...", AT24CXX_TEST_VALUE);
        
        /* 写入测试值 */
        ret = at24cxx_write_one_byte(test_addr, AT24CXX_TEST_VALUE);
        if (ret != AT24CXX_OK)
        {
            log_e("写入测试值失败");
            return AT24CXX_ERROR_CHECK;
        }
        
        /* 重新读取验证 */
        ret = at24cxx_read_one_byte(test_addr, &temp);
        if (ret != AT24CXX_OK || temp != AT24CXX_TEST_VALUE)
        {
            log_e("%s检测失败！请检查硬件连接", at24cxx_get_model_name());
            return AT24CXX_ERROR_CHECK;
        }
        
        log_i("%s检测成功 (容量:%u字节)", at24cxx_get_model_name(), at24cxx_get_capacity());
        return AT24CXX_OK;
    }
}

/**
 * @brief       从AT24CXX指定地址读取一个字节
 *
 * @param[in]   addr: 要读取的EEPROM地址 (0 ~ EE_TYPE)
 * @param[out]  data: 数据指针，用于存储读取的字节
 *
 * @retval      AT24CXX_OK: 读取成功
 * @retval      AT24CXX_ERROR_PARAM: 参数错误（data为NULL）
 * @retval      AT24CXX_ERROR_ADDR: 地址越界
 * @retval      AT24CXX_ERROR_I2C: I2C通信错误
 *
 * @note        支持AT24C01~AT24C256所有型号
 *              自动处理不同型号的地址寻址方式：
 *              - AT24C16及以下：使用器件地址的高位表示存储器高位地址
 *              - AT24C16以上：使用2字节地址寻址
 */
int8_t at24cxx_read_one_byte(uint16_t addr, uint8_t *data)
{
    /* 参数检查 */
    if (data == NULL)
    {
        log_e("参数错误: data指针为NULL");
        return AT24CXX_ERROR_PARAM;
    }
    
    /* 地址越界检查 */
    if (addr > EE_TYPE)
    {
        log_e("地址越界: addr=%u, max=%u", addr, EE_TYPE);
        return AT24CXX_ERROR_ADDR;
    }
    
#if (USE_HARDWARE_I2C == 1)
    /* 使用硬件I2C */
    uint8_t dev_addr;
    IIC_Error_e result;
    
    /* 根据不同的24CXX型号设置设备地址 */
    if (EE_TYPE > AT24C16)
    {
        /* 24C32及以上：使用16位地址 */
        dev_addr = AT24CXX_DEVICE_ADDR_BASE;
        result = IIC_Read_Mem(dev_addr, addr, I2C_MEMADD_SIZE_16BIT, data, 1);
    }
    else
    {
        /* 24C16及以下：使用设备地址高位表示高地址 */
        dev_addr = AT24CXX_DEVICE_ADDR_BASE + ((addr >> 8) << 1);
        result = IIC_Read_Mem(dev_addr, addr & 0xFF, I2C_MEMADD_SIZE_8BIT, data, 1);
    }
    
    if (result != IIC_OK)
    {
        log_e("硬件I2C读取失败: addr=0x%04X", addr);
        return AT24CXX_ERROR_I2C;
    }
    
    return AT24CXX_OK;
    
#else
    /* 软件I2C实现 */
    iic_start();
    
    /* 根据不同的24CXX型号, 发送高位地址
     * 1, 24C16以上的型号, 分2个字节发送地址
     * 2, 24C16及以下的型号, 分1个低字节地址 + 占用器件地址的bit1~bit3位 用于表示高位地址, 最多11位地址
     *    对于24C01/02, 其器件地址格式(8bit)为: 1  0  1  0  A2  A1  A0  R/W
     *    对于24C04,    其器件地址格式(8bit)为: 1  0  1  0  A2  A1  a8  R/W
     *    对于24C08,    其器件地址格式(8bit)为: 1  0  1  0  A2  a9  a8  R/W
     *    对于24C16,    其器件地址格式(8bit)为: 1  0  1  0  a10 a9  a8  R/W
     *    R/W      : 读/写控制位 0,表示写; 1,表示读;
     *    A0/A1/A2 : 对应器件的1,2,3引脚(只有24C01/02/04/8有这些脚)
     *    a8/a9/a10: 对应存储整列的高位地址, 11bit地址最多可以表示2048个位置,可以寻址24C16及以内的型号
     */
    if (EE_TYPE > AT24C16)
    {
        iic_send_byte(AT24CXX_DEVICE_ADDR_BASE);
        if (iic_wait_ack() != 0)
        {
            iic_stop();
            log_e("软件I2C无ACK: 发送设备地址");
            return AT24CXX_ERROR_I2C;
        }
        iic_send_byte(addr >> 8);
    }
    else
    {
        iic_send_byte(AT24CXX_DEVICE_ADDR_BASE + ((addr >> 8) << 1));
    }
    
    if (iic_wait_ack() != 0)
    {
        iic_stop();
        log_e("软件I2C无ACK: 发送地址");
        return AT24CXX_ERROR_I2C;
    }
    
    iic_send_byte(addr & 0xFF);
    if (iic_wait_ack() != 0)
    {
        iic_stop();
        log_e("软件I2C无ACK: 发送低地址");
        return AT24CXX_ERROR_I2C;
    }
    
    iic_start();
    iic_send_byte(AT24CXX_DEVICE_ADDR_READ);
    if (iic_wait_ack() != 0)
    {
        iic_stop();
        log_e("软件I2C无ACK: 进入读模式");
        return AT24CXX_ERROR_I2C;
    }
    
    *data = iic_read_byte(0);
    iic_stop();
    
    return AT24CXX_OK;
#endif
}

/**
 * @brief       向AT24CXX指定地址写入一个字节
 *
 * @param[in]   addr: 要写入的EEPROM地址 (0 ~ EE_TYPE)
 * @param[in]   data: 要写入的数据字节
 *
 * @retval      AT24CXX_OK: 写入成功
 * @retval      AT24CXX_ERROR_ADDR: 地址越界
 * @retval      AT24CXX_ERROR_I2C: I2C通信错误
 *
 * @note        写入后自动延时等待EEPROM内部写周期完成
 * @warning     频繁写入会影响EEPROM寿命（约100万次擦写），建议合理控制写入频率
 */
int8_t at24cxx_write_one_byte(uint16_t addr, uint8_t data)
{
    /* 地址越界检查 */
    if (addr > EE_TYPE)
    {
        log_e("地址越界: addr=%u, max=%u", addr, EE_TYPE);
        return AT24CXX_ERROR_ADDR;
    }
    
#if (USE_HARDWARE_I2C == 1)
    /* 使用硬件I2C */
    uint8_t dev_addr;
    IIC_Error_e result;
    
    /* 根据不同的24CXX型号设置设备地址 */
    if (EE_TYPE > AT24C16)
    {
        /* 24C32及以上：使用16位地址 */
        dev_addr = AT24CXX_DEVICE_ADDR_BASE;
        result = IIC_Write_Mem(dev_addr, addr, I2C_MEMADD_SIZE_16BIT, &data, 1);
    }
    else
    {
        /* 24C16及以下：使用设备地址高位表示高地址 */
        dev_addr = AT24CXX_DEVICE_ADDR_BASE + ((addr >> 8) << 1);
        result = IIC_Write_Mem(dev_addr, addr & 0xFF, I2C_MEMADD_SIZE_8BIT, &data, 1);
    }
    
    if (result != IIC_OK)
    {
        log_e("硬件I2C写入失败: addr=0x%04X", addr);
        return AT24CXX_ERROR_I2C;
    }
    
    AT24CXX_DELAY_MS(AT24CXX_WRITE_DELAY_MS);  /* EEPROM写入延时 */
    return AT24CXX_OK;
    
#else
    /* 软件I2C实现 */
    iic_start();
    
    if (EE_TYPE > AT24C16)
    {
        iic_send_byte(AT24CXX_DEVICE_ADDR_BASE);
        if (iic_wait_ack() != 0)
        {
            iic_stop();
            log_e("软件I2C无ACK: 发送设备地址");
            return AT24CXX_ERROR_I2C;
        }
        iic_send_byte(addr >> 8);
    }
    else
    {
        iic_send_byte(AT24CXX_DEVICE_ADDR_BASE + ((addr >> 8) << 1));
    }
    
    if (iic_wait_ack() != 0)
    {
        iic_stop();
        log_e("软件I2C无ACK: 发送地址");
        return AT24CXX_ERROR_I2C;
    }
    
    iic_send_byte(addr & 0xFF);
    if (iic_wait_ack() != 0)
    {
        iic_stop();
        log_e("软件I2C无ACK: 发送低地址");
        return AT24CXX_ERROR_I2C;
    }
    
    iic_send_byte(data);
    if (iic_wait_ack() != 0)
    {
        iic_stop();
        log_e("软件I2C无ACK: 发送数据");
        return AT24CXX_ERROR_I2C;
    }
    
    iic_stop();
    AT24CXX_DELAY_MS(AT24CXX_WRITE_DELAY_MS);
    
    return AT24CXX_OK;
#endif
}

/**
 * @brief       从AT24CXX指定地址开始读取多个字节
 *
 * @param[in]   addr: 起始读取地址 (0 ~ EE_TYPE)
 * @param[out]  pbuf: 数据缓冲区指针，用于存储读取的数据
 * @param[in]   len: 要读取的数据长度（字节数）
 *
 * @retval      AT24CXX_OK: 读取成功
 * @retval      AT24CXX_ERROR_PARAM: 参数错误
 * @retval      AT24CXX_ERROR_ADDR: 地址越界
 * @retval      其他: 读取过程中的错误码
 *
 * @note        确保缓冲区有足够空间存储读取的数据
 *              确保读取地址范围不超出EEPROM容量
 */
int8_t at24cxx_read(uint16_t addr, uint8_t *pbuf, uint16_t len)
{
    uint16_t i;
    int8_t ret;
    
    /* 参数检查 */
    if (pbuf == NULL || len == 0)
    {
        log_e("参数错误: pbuf=NULL 或 len=0");
        return AT24CXX_ERROR_PARAM;
    }
    
    /* 地址越界检查 */
    if (addr + len > (EE_TYPE + 1))
    {
        log_e("地址越界: addr=%u, len=%u, max=%u", addr, len, EE_TYPE + 1);
        return AT24CXX_ERROR_ADDR;
    }
    
    /* 逐字节读取 */
    for (i = 0; i < len; i++)
    {
        ret = at24cxx_read_one_byte(addr + i, &pbuf[i]);
        if (ret != AT24CXX_OK)
        {
            log_e("读取失败: addr=0x%04X", addr + i);
            return ret;
        }
    }
    
    log_d("读取成功: addr=0x%04X, len=%u", addr, len);
    return AT24CXX_OK;
}

/**
 * @brief       向AT24CXX指定地址开始写入多个字节
 *
 * @param[in]   addr: 起始写入地址 (0 ~ EE_TYPE)
 * @param[in]   pbuf: 数据缓冲区指针，包含要写入的数据
 * @param[in]   len: 要写入的数据长度（字节数）
 *
 * @retval      AT24CXX_OK: 写入成功
 * @retval      AT24CXX_ERROR_PARAM: 参数错误
 * @retval      AT24CXX_ERROR_ADDR: 地址越界
 * @retval      其他: 写入过程中的错误码
 *
 * @note        每个字节写入后都有延时，确保EEPROM内部写周期完成
 * @warning     频繁写入会影响EEPROM寿命
 */
int8_t at24cxx_write(uint16_t addr, const uint8_t *pbuf, uint16_t len)
{
    uint16_t i;
    int8_t ret;
    
    /* 参数检查 */
    if (pbuf == NULL || len == 0)
    {
        log_e("参数错误: pbuf=NULL 或 len=0");
        return AT24CXX_ERROR_PARAM;
    }
    
    /* 地址越界检查 */
    if (addr + len > (EE_TYPE + 1))
    {
        log_e("地址越界: addr=%u, len=%u, max=%u", addr, len, EE_TYPE + 1);
        return AT24CXX_ERROR_ADDR;
    }
    
    /* 逐字节写入 */
    for (i = 0; i < len; i++)
    {
        ret = at24cxx_write_one_byte(addr + i, pbuf[i]);
        if (ret != AT24CXX_OK)
        {
            log_e("写入失败: addr=0x%04X", addr + i);
            return ret;
        }
    }
    
    log_d("写入成功: addr=0x%04X, len=%u", addr, len);
    return AT24CXX_OK;
}

/**
 * @brief       获取AT24CXX型号名称
 *
 * @param       无
 *
 * @retval      型号名称字符串指针
 *
 * @note        支持AT24C01~AT24C256全系列芯片
 */
const char* at24cxx_get_model_name(void)
{
    switch (EE_TYPE)
    {
        case AT24C01:   return "AT24C01";
        case AT24C02:   return "AT24C02";
        case AT24C04:   return "AT24C04";
        case AT24C08:   return "AT24C08";
        case AT24C16:   return "AT24C16";
        case AT24C32:   return "AT24C32";
        case AT24C64:   return "AT24C64";
        case AT24C128:  return "AT24C128";
        case AT24C256:  return "AT24C256";
        default:        return "Unknown";
    }
}

/**
 * @brief       获取AT24CXX容量
 *
 * @param       无
 *
 * @retval      EEPROM容量（字节）
 *
 * @note        EE_TYPE定义的是最大地址，实际容量为EE_TYPE+1
 */
uint16_t at24cxx_get_capacity(void)
{
    return EE_TYPE + 1;
}

/**
 * @brief       获取AT24CXX页大小
 *
 * @param       无
 *
 * @retval      页大小（字节）
 *
 * @note        不同型号的AT24CXX页大小不同：
 *              - AT24C01/02: 8字节
 *              - AT24C04~16: 16字节
 *              - AT24C32~64: 32字节
 *              - AT24C128~256: 64字节
 */
uint8_t at24cxx_get_page_size(void)
{
    if (EE_TYPE <= AT24C02)
    {
        return 8;
    }
    else if (EE_TYPE <= AT24C16)
    {
        return 16;
    }
    else if (EE_TYPE <= AT24C64)
    {
        return 32;
    }
    else
    {
        return 64;
    }
}
